﻿using Microsoft.Extensions.Options;

namespace Sgr.BillNumbering.Services.Impl
{
    /// <summary>
    /// 默认编码生成器实现
    /// </summary>
    public class DefaultCodeGenerator : ICodeGenerator
    {
        private readonly CodeOptions _options;
        private readonly IEnumerable<ICodeGenerationStrategy> _strategies;
        private readonly ICodeSequence _sequenceGenerator;

        /// <summary>
        /// 构造函数，注入配置、策略集合和序列生成器
        /// </summary>
        public DefaultCodeGenerator(
            IOptions<CodeOptions> options,
            IEnumerable<ICodeGenerationStrategy> strategies,
            ICodeSequence sequenceGenerator)
        {
            _options = options.Value ?? throw new ArgumentNullException(nameof(options));
            _strategies = strategies ?? throw new ArgumentNullException(nameof(strategies));
            _sequenceGenerator = sequenceGenerator ?? throw new ArgumentNullException(nameof(sequenceGenerator));
        }

        /// <summary>
        /// 异步生成编码
        /// </summary>
        /// <param name="ruleName">规则名称</param>
        /// <param name="customPrefix">自定义前缀</param>
        /// <param name="cancellationToken">取消令牌</param>
        /// <returns>生成的编码字符串任务</returns>
        public Task<string> GenerateAsync(string ruleName, string customPrefix = "", CancellationToken cancellationToken = default)
        {
            var rule = GetRule(ruleName);
            var strategy = GetStrategy(rule.StrategyName);
            return strategy.GenerateAsync(rule, _sequenceGenerator, customPrefix, cancellationToken);
        }

        /// <summary>
        /// 获取指定名称的编码规则
        /// </summary>
        /// <param name="ruleName">规则名称</param>
        /// <returns>编码规则</returns>
        /// <exception cref="ArgumentException">未找到规则时抛出</exception>
        private CodeRule GetRule(string ruleName)
        {
            if (string.IsNullOrWhiteSpace(ruleName))
                throw new ArgumentException("规则名称不能为空。", nameof(ruleName));

            var rule = _options.GetRule(ruleName);
            return rule ?? throw new ArgumentException($"未找到名称为 '{ruleName}' 的编码规则。", nameof(ruleName));
        }

        /// <summary>
        /// 获取指定名称的编码策略
        /// </summary>
        /// <param name="strategyName">策略名称</param>
        /// <returns>编码策略</returns>
        /// <exception cref="ArgumentException">未找到策略时抛出</exception>
        private ICodeGenerationStrategy GetStrategy(string strategyName)
        {
            if (string.IsNullOrWhiteSpace(strategyName))
                throw new ArgumentException("策略名称不能为空。", nameof(strategyName));

            var strategy = _strategies.FirstOrDefault(s => s.StrategyName == strategyName) ?? throw new ArgumentException($"未找到名称为 '{strategyName}' 的编码策略。", nameof(strategyName));
            return strategy;
        }
    }
}